package cn.iocoder.yudao.module.pay.splitting.service.core;

import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.framework.business.basic.dao.repository.LockRedisRepository;
import cn.iocoder.yudao.framework.business.basic.service.impl.AbstractService;
import cn.iocoder.yudao.framework.common.exception.Assertions;
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
import cn.iocoder.yudao.module.api.infrastructure.config.ConfigApiV2;
import cn.iocoder.yudao.module.api.infrastructure.config.dto.PayConfigRespDTO;
import cn.iocoder.yudao.module.pay.framework.impl.mallbook.MallBookPayClientConfig;
import cn.iocoder.yudao.module.pay.framework.impl.mallbook.domain.CompleteNotifyResponse;
import cn.iocoder.yudao.module.pay.splitting.convert.SplittingMerchantConvert;
import cn.iocoder.yudao.module.pay.splitting.dao.PaySplittingMapper;
import cn.iocoder.yudao.module.pay.splitting.dao.SplittingMerchantMapper;
import cn.iocoder.yudao.module.pay.splitting.enums.SplittingChannelEnum;
import cn.iocoder.yudao.module.pay.splitting.enums.SplittingMerchantStatusEnum;
import cn.iocoder.yudao.module.pay.splitting.enums.SplittingMerchantTypeEnum;
import cn.iocoder.yudao.module.pay.splitting.pojo.po.SplittingMerchant;
import cn.iocoder.yudao.module.pay.splitting.pojo.vo.MallBookMerchantVO;
import cn.iocoder.yudao.module.pay.splitting.pojo.vo.MallBookSplittingVO;
import cn.iocoder.yudao.module.pay.splitting.pojo.vo.SplittingMerchantVO;
import com.trhui.mallbook.client.RegisterClient;
import com.trhui.mallbook.client.UserQueryClient;
import com.trhui.mallbook.domain.common.ApiResponse;
import com.trhui.mallbook.domain.common.BaseResponse;
import com.trhui.mallbook.domain.request.hf.HfNewRegisterRequest;
import com.trhui.mallbook.domain.request.hf.HfQueryUserRequest;
import com.trhui.mallbook.domain.response.hf.HfQueryUserResponse;
import com.trhui.mallbook.domain.response.hf.HfRegisterResponse;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.Map;
import java.util.Objects;

import static cn.iocoder.yudao.module.api.infrastructure.ConfigConstants.CONFIG_PAY;

/**
 * <pre>
 * OOoO0OOoO0OOOooo0oOOOO0OOOOO0oooOO0ooOOO0Ooooo0OOOOo0ooooO0OOooo0Ooooo0OOOOO
 *  这里是文件说明
 * OOoO0OOoO0OOOooo0oOOOO0OOOOO0oooOO0ooOOO0Ooooo0OOOOo0ooooO0OOooo0Ooooo0OOOOO
 * </pre>
 *
 * @author 山野羡民（1032694760@qq.com）
 * @since 2025/05/17
 */
@Service
@Slf4j
public class CoreSplittingMerchantService extends AbstractService<SplittingMerchant, SplittingMerchantVO> {
    private static final long TIMEOUT_MILLIS = 10 * DateUtils.SECOND_MILLIS;
    private static final String LOCK_KEY = "xianmin:pay:splitting-merchant:lock:%s";

    @Resource
    private LockRedisRepository lockRedisRepository;

    @Resource
    private SplittingMerchantMapper splittingMerchantMapper;
    @Resource
    private PaySplittingMapper paySplittingMapper;

    @Override
    public SplittingMerchantMapper getInjectedMapper() {
        return splittingMerchantMapper;
    }

    public SplittingMerchant getOrCreate(String mobile) {
        Assertions.notBlank(mobile, "未获取到手机号码");
        return lockRedisRepository.lock(String.format(LOCK_KEY, mobile), TIMEOUT_MILLIS, () -> {
            SplittingMerchant entity = getInjectedMapper().selectByMobile(mobile);
            if (entity == null) {
                entity = new SplittingMerchant();
                entity.setType(SplittingMerchantTypeEnum.Personal.getValue());
                entity.setName("匿名");
                entity.setStatus(SplittingMerchantStatusEnum.PENDING.getStatus());
                entity.setPhone(mobile);
                entity.setEidNo("");
                entity.setNotifyUrl("");
                entity.setChannelCode(SplittingChannelEnum.MallBook.getCode());
                entity.setChannelUserId("");
                getInjectedMapper().insert(entity);
            }
            return entity;
        });
    }

    public String register(Map<String, String> params, String body, Map<String, String> headers) {
        log.info("[splitting/register/notify][收到回调数据]\nparams: {}\nbody: {}\nheaders: {}", params, body, headers);
        MallBookMerchantVO vo = parseMerchantNotify(params, body, headers);
        SplittingMerchant entity = getOrCreate(vo.getMobile());
        if (Objects.equals(entity.getStatus(), SplittingMerchantStatusEnum.SUCCESS.getStatus())) {
            // 同样的异步消息可能会通知多次，因此接收异步消息的处理需做好幂等，保障多次接收到同样的消息处理后结果不变
            return JSONUtil.toJsonStr(vo);
        }
        if (Objects.equals(vo.getStatus(), SplittingMerchantStatusEnum.SUCCESS.getStatus())) {
            SplittingMerchant updateObj = new SplittingMerchant();
            updateObj.setId(entity.getId());
            updateObj.setStatus(SplittingMerchantStatusEnum.SUCCESS.getStatus());
            updateObj.setChannelCode(SplittingChannelEnum.MallBook.getCode());
            updateObj.setChannelUserId(vo.getChannelUserId());
            updateObj.setChannelNotifyData(JSONUtil.toJsonStr(vo.getRawData()));
            getInjectedMapper().updateById(updateObj);
        } else if (Objects.equals(vo.getStatus(), SplittingMerchantStatusEnum.FAILURE.getStatus())) {
            SplittingMerchant updateObj = new SplittingMerchant();
            updateObj.setId(entity.getId());
            updateObj.setStatus(SplittingMerchantStatusEnum.FAILURE.getStatus());
            updateObj.setChannelCode(SplittingChannelEnum.MallBook.getCode());
            updateObj.setChannelErrorCode(vo.getChannelErrorCode());
            updateObj.setChannelErrorMsg(vo.getChannelErrorMsg());
            updateObj.setChannelNotifyData(JSONUtil.toJsonStr(vo.getRawData()));
            getInjectedMapper().updateById(updateObj);
        }
        return JSONUtil.toJsonStr(vo);
    }

    public String complete(Map<String, String> params, String body, Map<String, String> headers) {
        log.info("[splitting/complete/notify][收到回调数据]\nparams: {}\nbody: {}\nheaders: {}", params, body, headers);
        MallBookSplittingVO vo;
        ApiResponse response = MallBookPayClientConfig.Holder.INSTANCE.validateApiResponse(params);
        // 验签通过，处理业务
        // {
        //    "merOrderId": "MB17531912549297214",
        //    "parameter1": "UPY202507121155467549",
        //    "status": "2",
        //    "statusMsg": "订单已冻结，请解冻后再进行支付确认"
        // }
        //HfCompleteResponse data = JSONUtil.parseObj(response.getResult()).toBean(HfCompleteResponse.class);
        CompleteNotifyResponse data = JSONUtil.parseObj(response.getResult()).toBean(CompleteNotifyResponse.class);
        // 异步分账状态：0-待处理、1-成功、2-失败
        if ("1".equals(data.getStatus())) {
            vo = MallBookSplittingVO.successOf(data.getParameter1(), data.getMerOrderId(), response);
        } else if ("2".equals(data.getStatus())) {
            vo = MallBookSplittingVO.failureOf(data.getParameter1(), data.getMerOrderId(), response.getCode(), data.getStatusMsg(), response);
        } else {
            vo = MallBookSplittingVO.waitingOf(data.getParameter1(), data.getMerOrderId(), response);
        }
        paySplittingMapper.updateResult(vo.getPayNo(), vo);
        return JSONUtil.toJsonStr(vo);
    }

    public SplittingMerchantVO syncInfoIfNecessary(String mobile, String realName, String eidNo) {
        String notifyUrl = SpringUtil.getBean(ConfigApiV2.class).getConfig(CONFIG_PAY, PayConfigRespDTO.class).getMerchantNotifyUrl();
        SplittingMerchant entity = getOrCreate(mobile);
        boolean shouldUpdate = false;
        // 分账账户信息变动，则自动更新（负责人姓名及身份证号码将进行人证二要素核验）
        if (!Objects.equals(entity.getPhone(), mobile)
            || !Objects.equals(entity.getName(), realName)
            || !Objects.equals(entity.getEidNo(), eidNo)) {
            entity.setChannelCode(SplittingChannelEnum.MallBook.getCode());
            entity.setPhone(mobile);
            entity.setName(realName);
            entity.setEidNo(eidNo);
            entity.setNotifyUrl(notifyUrl);
            shouldUpdate = true;
        }
        // 未注册分账账户到渠道，则自动注册
        if (Objects.equals(entity.getStatus(), SplittingMerchantStatusEnum.PENDING.getStatus())) {
            MallBookMerchantVO mallBookMerchantVO = registerMerchant(mobile, realName, eidNo, notifyUrl);
            entity.setChannelCode(SplittingChannelEnum.MallBook.getCode());
            entity.setChannelUserId(mallBookMerchantVO.getChannelUserId());
            entity.setChannelErrorCode(mallBookMerchantVO.getChannelErrorCode());
            entity.setChannelErrorMsg(mallBookMerchantVO.getChannelErrorMsg());
            entity.setChannelNotifyData(JSONUtil.toJsonStr(mallBookMerchantVO.getRawData()));
            entity.setStatus(mallBookMerchantVO.getStatus());
            if (Objects.equals(mallBookMerchantVO.getStatus(), SplittingMerchantStatusEnum.SUCCESS.getStatus())) {
                entity.setChannelErrorCode(null);
                entity.setChannelErrorMsg(null);
            }
            shouldUpdate = true;
        }
        if (shouldUpdate) {
            getInjectedMapper().updateById(entity);
        }
        return SplittingMerchantConvert.INSTANCE.toViewObject(entity);
    }

    private static MallBookMerchantVO registerMerchant(String mobile, String realName, String eidNo, String notifyUrl) {
        // 未注册分账商户到渠道则自动注册（默认固定为小微商户的原因：MallBook 校验实名信息自动审核通过，非小微商户需要异步审核营业执照等信息）
        // 接口文档，参阅：https://o2yyifwsjv.feishu.cn/docx/WaV7diAKMoNwt2xsfRVcXwxZn3d#KBg0dJI0Zo9xrhxxS9ucu5WInqc
        HfNewRegisterRequest request = new HfNewRegisterRequest();
        request.setMerchantNo(MallBookPayClientConfig.Holder.INSTANCE.getMerchantNo());
        request.setMerOrderId(MallBookPayClientConfig.Holder.INSTANCE.generateRequestNo());
        /*
         * 业务系统会员ID(必填) 字段长度最长：32位
         * 业务系统会员 ID 每次变更将会注册一个新的会员账户，注册失败时可使用原业务系统会员 ID 再次调用mallbook 进行资料变更
         */
        request.setMerUserId(mobile);
        /*
         * 子商户手机号(必填) 字段长度最长：11位
         * 小微：商户手机号
         * 非小微：法人手机号
         */
        request.setPhone(mobile);
        /*
         * 子商户类型(0 小微 1个体工商户  2 企业) (必填) 字段长度最长：1位
         */
        request.setUserType("0");
        /*
         * 子商户名称 (必填) 字段长度最长：64位
         * 小微：证件姓名
         * 非小微：营业执照名称
         */
        request.setUserName(realName);
        /*
         * 证件类型
         * 小微：商户证件类型
         * 00：身份证
         * 01：护照
         * 03：台胞证
         * 04：回乡证
         * 05：港澳台居住证
         * 非小微：法人证件类型
         * 仅支持00：身份证
         */
        request.setCertType("00");
        /*
         * 身份证号码(小微：个人身份证号码；个体和企业：法人身份证号码) (必填) 字段长度最长：20位
         */
        request.setCertId(eidNo);
        /*
         * 后台回调地址 (必填) 字段长度最长：256位
         */
        request.setNotifyUrl(notifyUrl);
        request.setContName(realName);
        request.setContPhone(mobile);
        BaseResponse<HfRegisterResponse> response = RegisterClient.hfRegister(request);
        //{"code":"1001","msg":"数据验证失败： certType: 证件类型不能为空","date":"1747637541527","version":"1.1.0"}
        //{"code":"1102","msg":"子商户已注册成功，不可重复注册","date":"1747634054732","version":"1.3.0"}
        log.info("RegisterClient.hfRegister: code={}, msg={}", response.getCode(), response.getMsg());
        if (response.getMsg().contains("注册成功")) {
            return getMerchant(mobile);
        }
        Assertions.isTrue(response.success(), response.getMsg());
        //{"result":"{\"errMsg\":\"认证不一致(不通过)\",\"merOrderId\":\"MB1747615898908\",\"merUserId\":\"1\",\"phone\":\"13800138000\",\"status\":2}","code":"0000","msg":"操作成功","date":"1747615900473","version":"1.3.0"}
        HfRegisterResponse data = response.getData();
        // 注册状态：0-待处理、1-成功、2-失败
        if ("1".equals(data.getStatus())) {
            return MallBookMerchantVO.successOf(mobile, data.getUserId(), response);
        }
        if ("2".equals(data.getStatus())) {
            return MallBookMerchantVO.failureOf(mobile, response.getCode(), data.getErrMsg(), response);
        }
        return MallBookMerchantVO.waitingOf(mobile, response);
    }

    private static MallBookMerchantVO getMerchant(String mobile) {
        // 接口文档，参阅：https://o2yyifwsjv.feishu.cn/docx/WaV7diAKMoNwt2xsfRVcXwxZn3d#doxcnzFHi5kciWaSVBae2vblGwc
        HfQueryUserRequest request = new HfQueryUserRequest();
        request.setMerchantNo(MallBookPayClientConfig.Holder.INSTANCE.getMerchantNo());
        request.setMerOrderId(MallBookPayClientConfig.Holder.INSTANCE.generateRequestNo());
        /*
         * 业务系统会员ID(必填) 字段长度最长：32位
         */
        request.setMerUserId(mobile);
        BaseResponse<HfQueryUserResponse> response = UserQueryClient.hfQuery(request);
        log.info("UserQueryClient.hfQuery: code={}, msg={}", response.getCode(), response.getMsg());
        Assertions.isTrue(response.success(), response.getMsg());
        HfQueryUserResponse data = response.getData();
        // 注册状态：0-待处理、1-成功、2-失败
        if ("1".equals(data.getStatus())) {
            return MallBookMerchantVO.successOf(mobile, data.getUserId(), response);
        }
        if ("2".equals(data.getStatus())) {
            return MallBookMerchantVO.failureOf(mobile, response.getCode(), data.getErrorMsg(), response);
        }
        return MallBookMerchantVO.waitingOf(mobile, response);
    }

    private static MallBookMerchantVO parseMerchantNotify(Map<String, String> params, String body, Map<String, String> headers) {
        ApiResponse response = MallBookPayClientConfig.Holder.INSTANCE.validateApiResponse(params);
        // 验签通过，处理业务
        HfRegisterResponse data = JSONUtil.parseObj(response.getResult()).toBean(HfRegisterResponse.class);
        // 注册状态：0-待处理、1-成功、2-失败
        if ("1".equals(data.getStatus())) {
            return MallBookMerchantVO.successOf(data.getPhone(), data.getUserId(), response);
        }
        if ("2".equals(data.getStatus())) {
            return MallBookMerchantVO.failureOf(data.getPhone(), response.getCode(), data.getErrMsg(), response);
        }
        return MallBookMerchantVO.waitingOf(data.getPhone(), response);
    }

}
